//=====================================================================
//
//  relexing is taking a thing and returning a string representing its
//  code-friendly name. this is usually what was lexed, hence the term.
//
//=====================================================================
#ifndef KALEIDOSCOPE_RELEX_HPP
#define KALEIDOSCOPE_RELEX_HPP
//=====================================================================
#include <atma/assert.hpp>
//=====================================================================
#include <sooty/frontend/syntactic_analysis/parseme.hpp>
//=====================================================================
#include <kaleidoscope/kaleidoscope.hpp>
#include <kaleidoscope/frontend/syntactical_analysis/marshall.hpp>
//=====================================================================
KALEIDOSCOPE_BEGIN
namespace relex {
//=====================================================================
	
	std::string type(atma::sooty::const_parseme_ptr_ref N);
	
	inline std::string function(atma::sooty::const_parseme_ptr_ref N)
	{
		ATMA_ASSERT(N->id == ids::function);
		
		std::string result = marshall::name(N)->value.string + "(";
		
		atma::sooty::parseme_container::const_iterator i = 
			marshall::function::parameter_list(N)->children.begin();
		
		for ( ; i != marshall::function::parameter_list(N)->children.end(); ++i)
		{
			if (i != marshall::function::parameter_list(N)->children.begin())
				result += ", ";
			result += type(*i);
		}
		
		result += ")";
		
		return result;
		
	}
	
	inline std::string function_call(atma::sooty::const_parseme_ptr_ref N)
	{
		ATMA_ASSERT(N->id == ids::function_call);

		std::string result = marshall::name(N)->value.string + "(";

		atma::sooty::parseme_container::const_iterator i = 
			marshall::function_call::parameter_list(N)->children.begin();

		for ( ; i != marshall::function_call::parameter_list(N)->children.end(); ++i)
		{
			if (i != marshall::function_call::parameter_list(N)->children.begin())
				result += ", ";
			result += type(*i);
		}

		result += ")";

		return result;
	}
	
	inline std::string type(atma::sooty::const_parseme_ptr_ref N)
	{
		switch (N->id) {
			case ids::int_type:
			case ids::int_literal:
				return "int";
			
			case ids::function_call:
				return marshall::name(N)->value.string;

			case ids::identifier:
				ATMA_ASSERT(false && "maybe shouldn't be here??");
			
			case ids::parameter:
				return type(marshall::parameter::type(N));
		}
		
		ATMA_ASSERT(false && "relex::type encountered bad id");
		
		return std::string();
	}
	
	
	
	
	inline const atma::sooty::file_position& file_position(atma::sooty::parseme_ptr N)
	{
		using namespace atma::sooty;
		
		if (N->file_position != atma::sooty::file_position(-1, -1))
			return N->file_position;
		
		if (N->parent.expired()) return N->file_position;
		
		parseme_ptr parent = atma::sooty::parseme_ptr(N->parent);
		
		// search all entries before us
		parseme_container::const_iterator end =
			std::find(parent->children.begin(), parent->children.end(), N);
			
		for (parseme_container::const_iterator i = parent->children.begin(); i != end; ++i)
		{
			if ((*i)->file_position != atma::sooty::file_position(-1, -1))
				return (*i)->file_position;
		}
		
		// recurse up the tree
		return file_position(parent);
	}
	
	
	
	
	
//=====================================================================
} // namespace relex
KALEIDOSCOPE_CLOSE
//=====================================================================
#endif
//=====================================================================
